1.19. Поведение системы
Поведение системы
Конфигурация и параметры
Программы не могут работать в вакууме – им всегда нужна какая-то базовая инструкция, содержащая базовые правила – настройки (параметры) или конфигурация.

★ Конфигурация – файлы (например, формата .config или .json), или переменные среды, определяющие поведение программы. Конфигурация состоит из конфигурационных единиц.
★ Конфигурационная единица — минимальный элемент настройки программы, задающий конкретное значение параметра, определяющего её поведение. Это атом конфигурации: одна «настройка» — одна единица.
Конфигурационные единицы существуют в разных формах, но всегда состоят из ключа и значения.
Форматы представления:
| Формат | Структура | Пример конфигурационной единицы |
|---|---|---|
| INI | ключ=значение | port=8080 |
| JSON | "ключ": значение | "log_level": "debug" |
| YAML | ключ: значение | theme: dark |
| XML | <ключ>значение</ключ> | <max_connections>100</max_connections> |
| Переменная среды | ИМЯ=значение | DATABASE_URL=postgres://user:pass@localhost/db |
| Флаг командной строки | --ключ=значение или -k значение | --verbose, -p 3000 |
Типы значений конфигурационных единиц:
- Булевы:
true/false,on/off,1/0
—enable_tls=true,debug_mode=false - Числовые: целые (
max_workers=4), вещественные (timeout_sec=2.5) - Строковые: пути (
data_dir="/var/lib/app"), имена (app_name="InvoiceGenerator") - Списки и массивы:
allowed_origins:
- "https://example.com"
- "https://admin.example.com" - Вложенные структуры (объекты):
"database": {
"host": "localhost",
"port": 5432,
"pool_size": 10
}
Особенности конфигурационных единиц:
-
Гиерархия: единицы могут группироваться в секции или вложенные объекты для улучшения читаемости и логической группировки.
-
Приоритет источников: одна и та же единица может быть задана в нескольких местах. Обычно действует порядок приоритета (от самого сильного к слабому):
- Флаги командной строки,
- Переменные среды,
- Файл конфигурации (
config.json), - Значение по умолчанию (встроено в код).
Например,--port=9000переопределитport: 8080вconfig.yaml.
-
Валидация при загрузке: программа проверяет тип и допустимость значения.
port="abc"вызовет ошибку, так как порт должен быть целым числом от 1 до 65535. -
Изменяемость во время выполнения: некоторые программы поддерживают горячую перезагрузку конфигурации — чтение обновлённого файла без перезапуска (например, Nginx:
nginx -s reload).
Конфигурационная единица — это не «настройка в интерфейсе», а её техническое воплощение. Даже когда пользователь ставит галочку «Запускать при старте системы» в настройках приложения, где-то в settings.json появляется запись: "autostart": true.
Есть ещё понятие конфигурации как набора комплектующих – компонентов компьютера, но это значение мы не рассматриваем. Для нас конфигурация сейчас это набор правил, настроек или параметров, которые определяют поведение программы. Она позволяет адаптировать программное обеспечение под конкретные задачи без необходимости изменения его исходного кода.
Конфигурационные файлы (например, .config, .json, .ini, .yaml) содержат ключевые значения, которые программа считывает призапуске. Например, веб-сервер может использовать конфигурацию для определения порта, на котором он будет работать, или пути к файлам логов.
Главное преимущество конфигурации - возможность легко изменить поведение программы без пересборки или переписывания кода.
Например, если нужно перевести интерфейс программы на другой язык, достаточно изменить значение соответствующего параметра в конфигурационном файле.
★ Настройка программы – формирование конкретного варианта программы под свои задачи. Настройка — это процесс адаптации под конкретные требования, включая изменение языка интерфейса, выбор темы оформления, настройку производительности, определение путей к файлам. Часто выводятся в графический интерфейс, чтобы пользователи могли легко изменять их без углубления в технические детали, лишь выбирая значения в выпадающих списках, расставляя флаги (галочки).
★ Параметры – аргументы командной строки (дополнительные выражения к команде), к примеру, --debug. Они позволяют управлять поведением командной строки непосредственно при запуске. Параметры особенно полезны для системных администраторов и разработчиков, но также используется и ещё одно понятие. Иногда под параметрами подразумевают какой-то флаг, аргумент, ключ, который что-то определяет. Допустим, включение или выключение какого-то свойства или поведения программы. Их можно назвать всеми этими значениями - флаг, параметр, галочка. Именно поэтому часто разделы настроек называются «Параметры» - потому что это какой-то набор аргументов, где пользователь может расставить соответствующие значения.
И всё это - настройка, параметр - есть конфигурация - определение поведения.
Без конфигурации пришлось бы переписывать код для каждого изменения, допустим, смена языка интерфейса. А благодаря конфигурации всё хранится в легко редактируемом файле, зачастую даже вынесенного на интерфейс.
★ Параметры системы — значения, задающие глобальное состояние операционной системы или среды выполнения программ. Они влияют на поведение множества компонентов сразу: ядра, служб, приложений, командной строки.
Параметры системы делятся на категории по области действия и способу задания.
1. Параметры ядра (kernel parameters)
Конфигурационные настройки, управляющие работой ядра ОС. В Linux они доступны через виртуальную файловую систему procfs и sysfs.
Примеры:
vm.swappiness=10— насколько активно система будет использовать swap при нехватке RAM,net.core.somaxconn=1024— максимальное количество ожидающих подключений для сокета,kernel.panic=10— через сколько секунд перезагружать систему при критической ошибке.
Изменяются через:
/etc/sysctl.conf(постоянно),sysctl -w vm.swappiness=10(временно, до перезагрузки).
2. Системные политики и ограничения
Параметры, задающие рамки работы пользователей и процессов.
Примеры:
ulimit -n 4096— максимальное количество открытых файловых дескрипторов для процесса,/etc/security/limits.conf— лимиты на количество процессов, объём памяти, приоритет,- SELinux/AppArmor политики — разрешения на доступ к файлам, сетевым портам, системным вызовам.
3. Параметры времени и локализации
timedatectl set-timezone Europe/Moscow— часовой пояс,localectl set-locale LANG=ru_RU.UTF-8— язык и кодировка,LC_TIME,LC_MONETARY— формат даты, валюты для конкретного сеанса.
4. Параметры сетевой подсистемы
ip route add default via 192.168.1.1— шлюз по умолчанию,iptables -A INPUT -p tcp --dport 22 -j ACCEPT— правило фаервола,/etc/resolv.conf— DNS-серверы.
5. Параметры виртуальной машины (для Java, .NET)
-Xmx2g— максимальный объём кучи для JVM,-XX:+UseG1GC— выбор сборщика мусора,COMPlus_GCHeapHardLimit=0x80000000— лимит памяти для .NET GC.
Особенности параметров системы:
- Они действуют глобально или на уровне пользователя/процесса,
- Часто требуют прав администратора для изменения,
- Имеют приоритет над настройками отдельных программ (например, если система запрещает открытие портов < 1024, приложение не сможет запустить веб-сервер на порту 80 без
sudo), - Изменения могут требовать перезагрузки или перезапуска служб.
Параметры системы — это «правила дорожного движения» для всего программного стека. Они не определяют, что делает программа, но строго ограничивают, как она может это делать.
Поведение программы
★ Поведение программы — совокупность действий, которые программа выполняет в ответ на входные данные, команды, события или изменения состояния среды. Поведение — это то, как программа работает, а не что она делает в общих чертах.
Поведение определяется тремя основными факторами:
1. Исходный код
Алгоритмы, условия, циклы, вызовы функций — всё это задаёт логику. Например:
- «Если пользователь ввёл пароль короче 8 символов — показать ошибку»,
- «При получении HTTP-запроса GET
/api/users— вернуть JSON со списком пользователей».
2. Конфигурация
Настройки влияют на варианты поведения без изменения кода:
log_level=debug→ программа записывает подробные отладочные сообщения,cache_enabled=false→ каждый запрос идёт напрямую к базе данных, без кэширования,ui_theme=dark→ интерфейс отрисовывается в тёмных тонах.
3. Состояние среды
Внешние условия, от которых зависит реакция:
- Наличие файла
config.local.yaml→ программа загружает локальные переопределения, - Сетевая задержка
>5 сек → срабатывает таймаут и повторная попытка, - ОЗУ
<512 МБ → программа отключает необязательные функции для экономии памяти.
Примеры поведения:
| Ситуация | Поведение |
|---|---|
| Пользователь нажимает «Сохранить» | — Проверяется валидность формы, — Данные сериализуются в JSON, — Отправляется POST-запрос на /save, — При успехе — показывается зелёная нотификация, — При ошибке — красная и лог в консоль. |
| Сервер получает запрос к несуществующему URL | — Возвращается HTTP 404, — В лог пишется: WARN: route /xyz not found, — Пользователю отдаётся страница «404 — Страница не найдена». |
| Закончилось место на диске | — Программа прекращает запись логов, — Отправляет уведомление администратору, — Переходит в «режим только чтение». |
Поведение можно описать формально — через спецификации (например, OpenAPI для API), сценарии использования (use cases), конечные автоматы (состояния: idle → loading → success/error).
Хорошо спроектированная программа имеет предсказуемое поведение: одни и те же входные данные при одинаковой конфигурации и среде всегда приводят к одинаковому результату (детерминированность). Это основа тестирования и отладки.
Пересборка
★ Пересборка — процесс повторного запуска инструментов сборки (компилятора, линковщика, упаковщика) для получения нового исполняемого файла или артефакта на основе изменённого исходного кода или конфигурации.
Пересборка происходит после внесения изменений, которые влияют на итоговый результат:
- изменение
.c,.java,.pyфайлов, - обновление зависимостей (новая версия библиотеки),
- изменение параметров сборки (режим отладки → релиз),
- модификация ресурсов (картинки, строки локализации).
Этапы пересборки (на примере C++):
- Предобработка: подстановка
#include, развертывание#define. - Компиляция: каждый
.cpp→.o(объектный файл с машинным кодом). - Линковка: объединение
.o-файлов и библиотек →program.exe. - Постобработка: минификация, обфускация, добавление цифровой подписи.
Современные системы сборки оптимизируют пересборку:
- Инкрементальная сборка: перекомпилируются только изменившиеся файлы и их зависимости (
make,MSBuild), - Кэширование артефактов: повторное использование уже собранных объектов (
ccache,sccache), - Параллельная сборка: запуск нескольких компиляторов одновременно (
make -j8).
Примеры пересборки в разных средах:
| Среда | Команда | Что делает |
|---|---|---|
| Python (Nuitka) | nuitka --standalone app.py | Пересобирает app.py в автономный .exe |
| Java (Maven) | mvn clean compile | Очищает target/, компилирует .java → .class |
| .NET | dotnet build --configuration Release | Собирает проект в режиме оптимизации |
| Web (Webpack) | npm run build | Пересобирает JS/CSS/HTML в dist/ |
| Linux (make) | make && sudo make install | Пересобирает и устанавливает программу из исходников |
Пересборка — управляемый процесс, который гарантирует, что итоговый артефакт соответствует текущему состоянию кодовой базы. Без пересборки изменения в коде останутся «на бумаге».
★ Переписывание кода — процесс полной или частичной замены исходного кода программы с сохранением её внешнего поведения или с целенаправленным изменением архитектуры, стиля, производительности.
Переписывание отличается от обычного редактирования масштабом и целью. Это не «исправил баг», а «перестроил фундамент».
Виды переписывания:
| Тип | Цель | Пример |
|---|---|---|
| Рефакторинг | Улучшение структуры кода без изменения функциональности | Замена глобальных переменных на внедрение зависимостей; выделение повторяющегося кода в функцию. |
| Миграция на другой язык | Получение преимуществ новой платформы | Python-скрипт → переписан на Rust для скорости и отсутствия GIL. |
| Смена архитектуры | Перевод с монолита на микросервисы, или наоборот | Веб-приложение на PHP → фронтенд на React + бэкенд на Go. |
| Обновление устаревших решений | Замена deprecated API, библиотек, подходов | jQuery → Vanilla JS + modern fetch API; Python 2 → Python 3. |
| Оптимизация производительности | Снижение времени отклика, потребления памяти | Переписывание критического цикла на C и вызов из Python через ctypes. |
Причины переписывания:
- Технический долг: код стал нечитаемым, не тестируемым, хрупким.
- Ограничения языка/платформы: отсутствие нужных библиотек, плохая производительность, отсутствие поддержки.
- Изменение требований: нужно масштабирование, отказоустойчивость, поддержка новых ОС.
- Командные предпочтения: новая команда лучше знает другой стек технологий.
- Юридические аспекты: отказ от проприетарных компонентов в пользу open source.
Особенности процесса:
- Параллельная разработка: новая версия создаётся отдельно, пока старая продолжает работать (стратегия * strangler fig pattern*).
- Постепенный перевод: часть функций переносится постепенно, через API-адаптеры.
- Тестирование как основа: автоматические тесты (unit, integration) позволяют убедиться, что поведение не изменилось.
- Документирование изменений: фиксация причин, архитектурных решений, откат-планов.
Переписывание — серьёзное решение. Оно требует ресурсов, времени и чёткого понимания целей. Но иногда это единственный способ вывести проект на новый уровень качества и возможностей.
Переменные среды
Конфигурация может быть также представлена переменными среды, которые задают глобальные настройки для ОС или конкретных программ. Например, переменная LANG в Linux определяет язык системы, а %APPDATA% в Windows указывает путь к данным пользовательских приложений.
★ Переменная среды – текстовая переменная ОС, которая хранит какую-либо информацию, допустим, данные о настройках системы. Они задаются, к примеру, в реестре Windows.
Вот пример некоторых переменных среды в Windows:
| Имя переменной | Суть и назначение |
|---|---|
%APPDATA% | Настройки программ текущего пользователя. Пример: C:\Users\Admin\AppData |
%WINDIR% | Место установленной Windows. Пример: C:\Windows |
%PROGRAMFILES% | Стандартная папка установки приложений. Пример: C:\Program Files |
Примеры в Linux
| Имя переменной | Суть и назначение |
|---|---|
| USER | Имя текущего пользователя |
| HOME | Домашний каталог |
| LANG | Кодировка языка системы |
Переменные среды представляют собой набор системных настроек, которые используются в адресной строке проводника в Windows и в терминалах. Технически, это просто «ключ» (имя переменной) и «значение», и, если обратиться к имени, получим значение.
Программы не всегда являются независимыми. Часто, для «построения» и запуска программы, требуется некие «строительные материалы» и ресурсы, которые бы позволили в полном объеме функционировать. Это зависимости и необходимые компоненты. Типы зависимостей:
- Библиотеки;
- Фреймворки;
- Системные библиотеки.
В проекте приложения описывается набор зависимостей (список), который формируется благодаря менеджерам пакетов.
★ Переменные среды — пары «имя–значение», хранящиеся в памяти операционной системы и доступные всем процессам, запущенным в одной пользовательской сессии (или системно — для всех пользователей).
Они используются для передачи конфигурации без изменения кода: пути, ключи, режимы работы, параметры локализации.
Пример: запуск python
Когда вы вводите в терминале:
python script.py
Система выполняет следующие шаги:
-
Поиск исполняемого файла: оболочка (например,
bash) обращается к переменнойPATH— это список каталогов, разделённых двоеточием (:в Linux/macOS) или точкой с запятой (;в Windows).
ПримерPATHв Linux:/usr/local/bin:/usr/bin:/bin:/home/user/.local/binОболочка ищет файл с именем
pythonпоочерёдно в каждом из этих каталогов. -
Нахождение интерпретатора: допустим,
pythonнайден в/usr/bin/python3.11. Это символическая ссылка на реальный исполняемый файл. -
Запуск процесса: система создаёт новый процесс, загружает
python3.11, передаёт ему аргументы (script.py), и копирует текущие переменные среды в память нового процесса. -
Использование переменных внутри Python:
Сам интерпретатор и скрипты могут читать переменные:import os
db_url = os.getenv("DATABASE_URL", "sqlite:///default.db")
debug = os.getenv("DEBUG", "false").lower() == "true"Пример запуска с переопределением:
DEBUG=true DATABASE_URL=postgres://user:pass@localhost/app python script.py
Распространённые переменные, влияющие на Python:
| Переменная | Назначение | Пример значения |
|---|---|---|
PYTHONPATH | Дополнительные пути для поиска модулей | /opt/mylib:/home/user/project/utils |
VIRTUAL_ENV | Путь к активной виртуальной среде | /home/user/venv |
PYTHONIOENCODING | Кодировка stdin/stdout/stderr | utf-8 |
http_proxy / https_proxy | Прокси-серверы для сетевых запросов | http://proxy.corp:3128 |
TZ | Часовой пояс (если не задан в os.environ) | Europe/Moscow |
Как задать переменные:
- Временно (на сессию):
export LANG=ru_RU.UTF-8 - Для одной команды:
DEBUG=1 python app.py - Постоянно:
— В~/.bashrc,~/.profile,/etc/environment,
— В Windows — через «Система → Дополнительные параметры → Переменные среды».
Переменные среды — стандартный, кроссплатформенный способ конфигурирования поведения программ без изменения исходного кода и без правки файлов конфигурации. Они особенно важны в контейнерах (Docker), где каждый параметр часто передаётся через -e KEY=VALUE.
Библиотеки и фреймворки
Представим, что перед вами высококвалифицированный специалист, который решит вашу задачу – это будет программа. И этому специалисту для решения нужна стройплощадка (фреймворк) и ресурсы (библиотеки). Обладая площадкой и ресурсами, по чертежу (инструкциям) специалист всё выполнит, и вы получите результат. Но если какого-то ресурса нет, то специалист не возьмётся за работу – так и программа откажется работать.
Библиотеки - наборы предварительно написанного кода, которые решают конкретные задачи. Вместо того, чтобы писать код заново для обработки изображений, работы с сетью или математических вычислений, можно использовать готовые библиотеки. Они экономят время разработчиков и делают программы более надёжными, так как эти компоненты тщательно протестированы и поддерживаются сообществом.
Типы библиотек:
| Тип | Описание | Примеры |
|---|---|---|
| Стандартная библиотека | Входит в поставку языка или ОС | stdlib в Python, java.util в Java, libc в C |
| Системная библиотека | Часть ОС, обеспечивает доступ к её сервисам | glibc (Linux), Kernel32.dll (Windows), CoreFoundation (macOS) |
| Сторонняя библиотека | Создана сообществом или компанией, подключается отдельно | requests (Python), lodash (JS), OpenSSL (C) |
| Статическая библиотека | Код копируется в исполняемый файл на этапе сборки | .a (Linux), .lib (Windows) |
| Динамическая библиотека | Загружается в память во время выполнения | .so (Linux), .dll (Windows), .dylib (macOS) |
Примеры библиотек и их назначение:
| Библиотека | Язык/Платформа | Функционал |
|---|---|---|
requests | Python | Упрощённая отправка HTTP-запросов: r = requests.get("https://api.example.com") |
NumPy | Python | Работа с многомерными массивами, математические операции на высокой скорости |
React | JavaScript | Построение пользовательских интерфейсов через компоненты и виртуальный DOM |
OpenCV | C++/Python | Компьютерное зрение: распознавание лиц, обработка изображений |
fmt | C++ | Безопасное форматирование строк: fmt::format("Hello, {}!", name) |
log4j | Java | Гибкое логирование: уровни (DEBUG, INFO), вывод в файл/сеть/консоль |
Особенности библиотек:
- Чёткий контракт интерфейса: библиотека предоставляет публичный API — функции, классы, константы. Всё остальное скрыто (инкапсуляция).
- Версионирование: каждая библиотека имеет номер версии (часто по SemVer), чтобы отслеживать совместимость.
- Зависимости: библиотека сама может использовать другие библиотеки (транзитивные зависимости).
- Лицензирование: важно учитывать при коммерческом использовании (MIT, Apache 2.0 — разрешают; GPL — требуют открытия кода).
- Производительность: многие библиотеки написаны на низкоуровневых языках (C/C++) и предоставляют обёртки для высокоуровневых (Python, JS).
Системные библиотеки — это компоненты, которые обеспечивают взаимодействие программы с операционной системой, предоставляя доступ к базовым функциям, таким как работа с файловой системой, управление памятью или сетевые подключения.

Фреймворки — это всегда набор инструментов, шаблонов и правил, которые помогают разработчикам создавать приложения быстрее и эффективнее. Они представляют собой базовую структуру, в которой предстоит работать. Это может быть как набор библиотек и утилит для разработки, так и подход к разработке (алгоритмы, порядок и принципы).
★ Фреймворк — комплексная платформа, предоставляющая каркас для разработки приложений. Фреймворк определяет архитектуру, правила взаимодействия компонентов и часто включает в себя библиотеки, инструменты и шаблоны.
В отличие от библиотеки, вы вызываете библиотеку, а фреймворк вызывает вас (Inversion of Control — инверсия управления).
Ключевые признаки фреймворка:
- Каркас приложения: шаблон структуры проекта (папки
models/,views/,controllers/), - Жизненный цикл: фреймворк управляет запуском, обработкой запросов, завершением,
- Встроенные компоненты: маршрутизация, ORM, система шаблонов, аутентификация,
- Расширяемость через хуки и плагины: точки подключения собственной логики.
Примеры фреймворков:
| Фреймворк | Язык | Назначение | Особенности |
|---|---|---|---|
| Django | Python | Веб-приложения «из коробки» | «Batteries included»: админка, ORM, миграции, аутентификация — всё встроено. |
| Spring Boot | Java | Корпоративные сервисы | Автоконфигурация, внедрение зависимостей, интеграция с БД, очередями, облаками. |
| .NET MAUI | C# | Кроссплатформенные мобильные и десктопные приложения | Единый код для Windows, macOS, iOS, Android. |
| Unity | C# | Разработка игр и симуляций | Графический редактор сцен, физический движок, поддержка 2D/3D, ассет-стор. |
| TensorFlow/Keras | Python | Машинное обучение | Граф вычислений, автоматическое дифференцирование, GPU-ускорение. |
| Electron | JavaScript | Десктопные приложения на веб-технологиях | Chromium + Node.js — позволяет писать приложения как веб-сайты. |
Особенности фреймворков:
- Ограничение свободы выбора: фреймворк диктует, как писать код. Зато обеспечивает единообразие и предсказуемость.
- Высокая производительность «из коробки»: оптимизации уже встроены (кеширование, пул соединений, асинхронность).
- Большое сообщество и экосистема: документация, курсы, сторонние расширения, готовые решения (boilerplates).
- Сложность входа: требуется изучить не только язык, но и правила фреймворка.
- Риск vendor lock-in: переход на другой стек может потребовать полного переписывания.

Чтобы управлять зависимостями, разработчики используют менеджеры пакетов - специальные инструменты, которые автоматически загружают, устанавливают и обновляют необходимые компоненты. Каждый язык программирования или платформа обычно имеют собственные менеджеры пакетов:
- npm для JavaScript (Node.js);
- pip для Python;
- Maven или Gradle для Java;
- NuGet для .NET;
- Composer для PHP.
В проекте приложения создаётся файл, который описывает все необходимые зависимости. Это позволяет другим разработчикам воспроизвести среду разработки или развернуть приложение на другом компьютере. Менеджеры пакетов также следят за совместимостью версий зависимостей, что снижает риск конфликтов между компонентами.
Вычисление
★ Вычисление – процесс получения входных данных (допустим, чисел 2 и 3), применения операторов (+, -, * или /), и возвращения результата – допустим, 5 после операции 2+3.
Таким образом, если мы разберем «2 + 3 = 5», мы получим:
- 2 и 3 – операнды;
-
-
- оператор;
-
- 5 – возвращаемый результат.
★ Слово «возвращать» (англ. return) встречается в программировании очень часто, поэтому важно привыкнуть. Это как отправить задачу с исходными данными специалистами, чтобы он вам вернул результат.

★ Возвращение — завершающая фаза выполнения функции или метода, при которой результат её работы передаётся вызывающей стороне. Это не просто «конец работы», а передача управления и данных обратно по стеку вызовов.
Каждая функция в программе — как специалист, которому поручили задачу. Он берёт входные данные, выполняет действия, и возвращает результат. Без возврата работа остаётся «внутри» — она не влияет на остальную систему.
Как работает возврат:
- Функция получает аргументы (входные данные),
- Выполняет последовательность инструкций,
- В определённый момент достигает оператора
return, - Система:
- сохраняет значение после
return, - освобождает локальную память функции (стековый фрейм),
- передаёт управление обратно в точку вызова,
- подставляет возвращённое значение на место вызова функции.
- сохраняет значение после
Пример на Python:
def add(a, b):
result = a + b
return result # ← возврат значения
x = add(2, 3) # после возврата x получает значение 5
Чем возврат отличается от обычного выполнения:
| Аспект | Обычное выполнение | Возврат |
|---|---|---|
| Цель | Выполнение последовательности действий | Передача результата и выход из функции |
| Место в коде | Любая строка внутри тела | Только оператор return (или неявный возврат None/undefined) |
| Побочные эффекты | Может изменять глобальное состояние, писать в файл, отправлять запрос | Не обязан иметь побочные эффекты; чистые функции возвращают только результат |
| Контроль потока | Продолжение выполнения следующей инструкции | Немедленное прекращение работы функции, переход к вызывающему коду |
| Множественные точки выхода | Одно выполнение — один линейный путь (без ветвлений) | Функция может иметь несколько return в разных ветках (if/else) |
Особые случаи:
-
Неявный возврат:
В Python функция безreturnвозвращаетNone.
В JavaScript —undefined.
Это всё равно возврат, просто со значением по умолчанию. -
Возврат без значения:
В языках вроде C# или Java метод с типомvoidне возвращает данные, но всё равно выполняет возврат управления:void Log(string msg) {
Console.WriteLine(msg);
return; // необязательно, но допустимо
} -
Ранний возврат — распространённая техника:
def process_user(data):
if not data:
return False # сразу выходим, если данных нет
# ... остальная логика
Возврат — это интерфейс функции. Он определяет, что функция даёт внешнему миру. Хорошо спроектированный возврат делает код предсказуемым, тестируемым и композируемым.
Задачи и многозадачность.
Компьютеры делают много дел «одновременно». Как это работает?
На самом деле, процессор выполняет в одном ядре выполняет только одну инструкцию за раз, но благодаря тому, как он переключается миллионы раз в секунды, создаётся эффект параллельной работы. Представьте, что вы одновременно читаете эту книгу, готовите ужин и слушаете музыку. Вот как раз это три разных задачи, которые выполняются одновременно, обеспечивая многозадачность (мультизадачность, мультитаск). Но в терминологии мы можем путать многозадачность и многопоточность. Технически, они не одинаковы.
К задаче мы можем отнести процесс.
Процессы – изолированные задачи (допустим, программы – браузер, текстовый редактор), и это зачастую отдельная и независимая программа, которая имеет свою выделенную память и ресурсы.
★ Потоки – нити внутри одного процесса, по которым они движутся (например, загрузка файла). Своего рода часть процесса, потому зависима от него целиком. Самый простой пример – вкладки браузера. Браузер – отдельный процесс, а вкладки – некие «подпроцесс», которые запускаются как отдельные потоки, не блокируя друг друга, а работающие параллельно.
Процесс: автономный «контейнер»
Особенности:
- Имеет собственное адресное пространство — одна программа не может читать память другой напрямую,
- Обладает дескрипторами ресурсов: открытые файлы, сокеты, окна,
- Запускается из исполняемого файла и имеет точку входа (
main), - Жизненный цикл управляется ОС: создание, приостановка, завершение.
Примеры процессов:
| Процесс | Команда запуска | Что происходит |
|---|---|---|
explorer.exe | Автозапуск при входе в Windows | Управляет рабочим столом, проводником, панелью задач |
chrome | google-chrome | Создаёт несколько процессов: браузер, рендереры (по одному на вкладку), GPU, утилиты |
postgres | sudo systemctl start postgresql | Главный процесс (postmaster) порождает дочерние для каждого подключения |
notepad.exe | Двойной клик по .txt | Независимый процесс: закрытие одного блокнота не влияет на другой |
Связь процессов:
- Родительский процесс создаёт дочерний через
fork()(Linux) илиCreateProcess()(Windows), - Процессы могут обмениваться данными через:
— файлы,
— сокеты (локальные или сетевые),
— именованные каналы (pipe,named pipe),
— разделяемую память (требует синхронизации).
Поток: «нить исполнения» внутри процесса
Особенности:
- Все потоки одного процесса делят общую память: глобальные переменные, кучу, открытые файлы,
- Каждый имеет собственный стек — для локальных переменных и возвратов из функций,
- Переключение между потоками быстрее, чем между процессами (не требуется переключение адресного пространства),
- Потоки одного процесса могут блокировать друг друга, если работают с общими данными без синхронизации.
Примеры потоков:
| Сценарий | Потоки в действии |
|---|---|
| Веб-сервер (Node.js) | Один основной поток (event loop) + воркеры для тяжёлых операций (через worker_threads) |
| Текстовый редактор | Основной поток — интерфейс, фоновый поток — автосохранение каждые 30 секунд |
| Антивирус при сканировании | Один поток читает файлы с диска, другой — проверяет сигнатуры, третий — обновляет прогресс-бар |
| Игровой движок | Поток рендеринга (60 кадров/с), поток физики (120 Гц), поток звука, поток AI противников |
Синхронизация потоков:
mutex(взаимное исключение) — только один поток может входить в критическую секцию,semaphore— ограничение числа одновременных потоков,condition variable— ожидание наступления события («данные готовы»),atomic operations— операции, которые выполняются неделимо (например,fetch_add).
Визуальная аналогия:
- Процесс — это завод со своим зданием, складом и электропитанием,
- Потоки — рабочие линии внутри завода, использующие общий склад, но работающие независимо.
Процессы обеспечивают изоляцию и стабильность. Потоки обеспечивают производительность и отзывчивость.
У многозадачности есть риски. К примеру, если два потока будут работать с одной и той же переменной, будут ошибки, поэтому используются блокировки, где один поток блокируется и ждёт, пока закончит первый. Для решения проблем одновременной работы потоков, используется многопроцессорность (несколько ядер CPU), и асинхронность (что это такое, изучим чуть позже).
Операционная система
★ Операционная система управляет всем этим при помощи специальных планировщиков (Scheduler), которые решают, какой процесс или поток получит процессор, используя алгоритмы «по очереди» или по «приоритетности». Но для переключения современным процессорам нужно меньше 1мс, так что мы не замечает всего контекстного переключения, включающего в себя сохранение текущего процесса и загрузку состояния нового. При необходимости оптимизировать свою программу, программист может акцентировать своё внимание на работе потоков и использования всех вышеуказанных особенностей, добавляя искуственные блокировки, коллбэки и прочее.